package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.AliPayFeignApi;
import cn.wolfcode.feign.IntegraFeignlApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by wolfcode-lanxw
 */
@Service
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private AliPayFeignApi aliPayFeignApi;
    @Autowired
    private IntegraFeignlApi integraFeignlApi;
    @Value("${pay.returnUrl}")
    String returnUrl;
    @Value("${pay.notifyUrl}")
    String notifyUrl;

    @Override
    @Transactional
    public String doSeckill(Integer time, Long seckillId, Long phone) {
        //1.减少真实库存
        int stockCount = seckillProductMapper.decrStock(seckillId);
        if (stockCount == 0) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        //2.创建订单保存到数据库中
        String orderNO = createOrder(time, seckillId, phone);
        //3.往redis中存储数据
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(String.valueOf(time)), phone + ":" + seckillId);
        return orderNO;
    }

    private String createOrder(Integer time, Long seckillId, Long phone) {
        SeckillProductVo seckillProductVo = seckillProductService.find(seckillId, time);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderNo(IdGenerateUtil.get().nextId() + "");
        orderInfo.setCreateDate(new Date());
        orderInfo.setProductId(seckillProductVo.getProductId());
        orderInfo.setIntergral(seckillProductVo.getIntergral());
        //地址功能没有做
        orderInfo.setDeliveryAddrId(1L);
        orderInfo.setProductImg(seckillProductVo.getProductImg());
        orderInfo.setProductCount(seckillProductVo.getStockCount());
        orderInfo.setProductName(seckillProductVo.getProductName());
        orderInfo.setProductPrice(seckillProductVo.getProductPrice());
        orderInfo.setSeckillDate(new Date());
        orderInfo.setSeckillId(seckillId);
        orderInfo.setSeckillTime(time);
        orderInfo.setUserId(phone);
        orderInfo.setSeckillPrice(seckillProductVo.getSeckillPrice());
        orderInfoMapper.insert(orderInfo);
        return orderInfo.getOrderNo();
    }

    @Override
    @Transactional
    public void timeOutCancel(OrderMQResult orderMQResult) {
        //判断订单状态是为未支付装态
        OrderInfo orderInfo = orderInfoMapper.find(orderMQResult.getOrderNo());
        if (orderInfo != null) {
            //如果是未支付
            if (OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())) {
                //回补真实库存
                seckillProductMapper.incrStock(orderInfo.getSeckillId());
                //回补预库存
                seckillProductService.syncRedisStockCount(orderInfo.getSeckillTime(), orderInfo.getSeckillId());
                //修改本地标识
                rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, orderMQResult.getSeckillId());
                //修改订单状态
                orderInfoMapper.updateCancelStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_TIMEOUT);
            }
        }
    }

    @Override
    public OrderInfo find(String orderNo) {
        Object obj = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDERSYNC_HASH.getRealKey(""), orderNo);
        if (obj == null) {
            return null;
        }
        return JSON.parseObject(String.valueOf(obj), OrderInfo.class);
    }

    @Override
    @Transactional
    public String onlinePayment(String orderNo, int type) {
        PayVo payVo = new PayVo();
        OrderInfo orderInfo = find(orderNo);
        payVo.setSubject(orderInfo.getProductName());
        payVo.setTotalAmount(orderInfo.getSeckillPrice() + "");
        payVo.setOutTradeNo(orderNo);
        //没有设置这个字段，当前使用商品名称当作商品详情
        payVo.setBody(orderInfo.getProductName());
        payVo.setReturnUrl(returnUrl);
        payVo.setNotifyUrl(notifyUrl);
        //远程调用支付服务
        Result<String> result = aliPayFeignApi.payOnline(payVo);
        if (result != null && !result.hasError()) {
            return result.getData();
        }
        return null;
    }

    @Override
    @GlobalTransactional
    public void IntegralToPay(String orderNo, int type) {
        OrderInfo orderInfo = find(orderNo);
        //1.插入流水记录
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderNo);
        payLog.setPayType(type);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(dateFormat.format(new Date()));
        payLog.setTotalAmount(orderInfo.getSeckillPrice()+"");
        payLogMapper.insert(payLog);
        //2.远程调用积分业务减少积分
        OperateIntergralVo operateIntergralVo = new OperateIntergralVo();
        operateIntergralVo.setPk(orderNo);
        operateIntergralVo.setUserId(orderInfo.getUserId());
        operateIntergralVo.setValue(orderInfo.getIntergral());
        operateIntergralVo.setInfo(orderInfo.getProductName());
        Result<String> result = integraFeignlApi.IntegralToPay(operateIntergralVo);
        if (result == null || result.hasError()){
            if (SeckillCodeMsg.INTERGRAL_NOT_ENOUGH.getCode().equals(result.getCode())){
                throw new BusinessException(SeckillCodeMsg.INTERGRAL_NOT_ENOUGH);
            }else {
                throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
            }
        }
        //3.修改订单支付状态为已支付状态，并且是积分支付
        orderInfoMapper.changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_INTERGRAL);
    }

    @Override
    @Transactional
    public void paySuccess(String orderNo) {
        //查询当前订单的详情信息
        OrderInfo orderInfo = find(orderNo);
        //插入流水记录
        PayLog payLog = new PayLog();
        payLog.setPayType(OrderInfo.PAYTYPE_ONLINE);
        payLog.setTotalAmount(orderInfo.getSeckillPrice()+"");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(dateFormat.format(new Date()));
        payLog.setTradeNo(orderNo);
        payLogMapper.insert(payLog);
        //修改订单状态
        orderInfoMapper.changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_ONLINE);
    }

    @Override
    @Transactional
    public void refundOnline(OrderInfo orderInfo) {
        //插入一条流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundType(OrderInfo.PAYTYPE_ONLINE);
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundTime(new Date());
        refundLog.setRefundReason("重复买了，不想要了");
        //远程调用支付服务进行退款操作
        RefundVo refundVo = new RefundVo();
        refundVo.setOutTradeNo(orderInfo.getOrderNo());
        refundVo.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundVo.setRefundReason("重复买了，不想要了");
        Result<Boolean> result = aliPayFeignApi.refundOnline(refundVo);
        if (result == null || result.hasError() || !result.getData()){
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }
        //修改订单状态为退款状态
        orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(),OrderInfo.STATUS_REFUND);
        //回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }

    @Override
    @GlobalTransactional
    public void IntegralRefund(OrderInfo orderInfo) {
        //1.插入流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundType(OrderInfo.PAYTYPE_INTERGRAL);
        refundLog.setRefundAmount(orderInfo.getIntergral()+"");
        refundLog.setRefundTime(new Date());
        refundLog.setRefundReason("重复买了，不想要了");
        //2.远程调用积分服务加积分
        OperateIntergralVo operateIntergralVo = new OperateIntergralVo();
        operateIntergralVo.setPk(orderInfo.getOrderNo());
        operateIntergralVo.setValue(orderInfo.getIntergral());
        operateIntergralVo.setInfo(orderInfo.getProductName());
        operateIntergralVo.setUserId(orderInfo.getUserId());
        Result<String> result = integraFeignlApi.IntegralToRefund(operateIntergralVo);
        if (result == null || result.hasError()){
                throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
        //3.修改订单状态为退款装态
        int count = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(),OrderInfo.STATUS_REFUND);
        if (count == 0){
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }
        //int i = 1/0;
        //4.回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //5.回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //6.修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }
}
